/**
 * @file 数组工具类
 * @author 2025-07-04 10:28:00
 * @version 1.0.0
 * @description
 * 判断数组是否为空、
 * 根据key去重数组、
 * 根据key进行数组列求和、
 * 根据keys将数组多个列字段类型转换为同一个类型、
 * 将数组arr拆分成长度为len的多个子数组、
 * 取两个数组的交集intersection、
 * 取两个数组的差集difference、
 * 取两个数组的并集union、
 * 通用数组根据单个字段进行升降排序、
 * 对象数组根据多个字段进行升降排序、
 * 对象数组根据多个field进行分组、
 * 单选框数据不存在回显异常处理方案、
 * 多选框数据不存在回显异常处理方案
 */

/**
 * 判断数组是否为空 测试完成
 */
export function isEmpty(arr) {
	// 检查参数是否为 null 或 undefined
	if (arr === null || arr === undefined) {
		return true;
	}
	// 检查参数是否为数组类型
	if (!Array.isArray(arr)) {
		return true;
	}
	// 检查数组长度是否为 0
	return arr.length === 0;
}

/**
 * 根据key去重数组
 * @param arr
 * @param key
 * @returns {any[]}
 */
export function uniqueByKey(arr, key) {
	// 参数校验
	if (!Array.isArray(arr) || arr.length === 0 || !key) {
		return arr || [];
	}
	// 逻辑处理
	const map = new Map();
	arr.forEach(item => {
		if (!map.has(item[key])) {
			map.set(item[key], item);
		}
	});
	return Array.from(map.values());
}

/**
 * 根据key进行数组列求和
 * @param {Array} arr - 要进行求和操作的数组
 * @param {string} key - 用于指定求和的属性名
 * @returns {number} - 求和结果
 */
export function sumByKey(arr, key) {
	// 参数校验
	if (!Array.isArray(arr) || arr.length === 0 || !key) {
		return 0;
	}
	// 累加指定 key 的值
	return arr.reduce((sum, item) => {
		const value = Number(item[key]);
		return isNaN(value) ? sum : sum + value;
	}, 0);
}

/**
 * 根据keys将数组多个列字段类型转换为同一个类型
 * @param {Array} arr - 要处理的数组
 * @param {Array<string>} keys - 需要转换类型的字段名数组
 * @param {Function} typeConverter - 类型转换函数，如 Number、String 等
 * @returns {Array} - 转换后的数组
 */
export function convertToSameTypeByArrayKeys(arr, keys, typeConverter) {
	// 参数校验
	if (!Array.isArray(arr) || arr.length === 0 || !Array.isArray(keys) || keys.length === 0 || typeof typeConverter !==
		'function') {
		return arr;
	}

	return arr.map(item => {
		const newItem = {
			...item
		};
		keys.forEach(key => {
			if (newItem.hasOwnProperty(key)) {
				try {
					newItem[key] = typeConverter(newItem[key]);
				} catch (error) {
					console.warn(`转换字段 ${key} 类型时出错:`, error);
				}
			}
		});
		return newItem;
	});
}

/**
 * 将数组arr拆分成长度为len的多个子数组
 * @param {Array} arr - 要进行拆分的数组
 * @param {number} len - 每个子数组的长度
 * @returns {Array<Array>} - 拆分后的子数组组成的数组
 */
export function partition(arr, len) {
	// 参数校验
	if (!Array.isArray(arr) || arr.length === 0 || typeof m !== 'number' || len <= 0) {
		return [];
	}
	// 如果数组长度小于等于 m，直接返回数组
	if (arr.length <= len) {
		return arr;
	}
	// 存储拆分后的子数组
	const result = [];
	for (let i = 0; i < arr.length; i += len) {
		// 截取长度为 m 的子数组并添加到结果数组中
		result.push(arr.slice(i, i + len));
	}
	return result;
}

/**
 * 取两个数组的交集intersection函数
 * @param {Array} arr1 - 第一个数组
 * @param {Array} arr2 - 第二个数组
 * @returns {Array} - 两个数组的交集
 */
export function intersection(arr1, arr2) {
	const set2 = new Set(arr2);
	return arr1.filter(item => set2.has(item));
}

/**
 * 取两个数组的差集difference函数
 * @param {Array} arr1 - 第一个数组
 * @param {Array} arr2 - 第二个数组
 * @returns {Array} - 第一个数组相对于第二个数组的差集
 */
export function difference(arr1, arr2) {
	const set2 = new Set(arr2);
	return arr1.filter(item => !set2.has(item));
}

/**
 * 取两个数组的并集union函数
 * @param {Array} arr1 - 第一个数组
 * @param {Array} arr2 - 第二个数组
 * @returns {Array} - 两个数组的并集
 */
export function union(arr1, arr2) {
	return [...new Set([...arr1, ...arr2])];
}

/**
 * 通用数组根据单个字段进行升降排序 测试完成
 * @param {Array} arr - 要进行排序的数组
 * @param {string|null} key - 用于排序的属性名，如果不指定传null，则按数组元素本身进行排序
 * @param {boolean} [isAscending=true] - 是否升序排列，默认为 true
 * @returns {Array} - 排序后的数组
 */
export function sortByKey(arr, key, isAscending = true) {
	// 参数校验，只检查数组是否有效
	if (!Array.isArray(arr) || arr.length === 0) {
		return arr;
	}

	return [...arr].sort((a, b) => {
		let valueA = key ? a[key] : a;
		let valueB = key ? b[key] : b;

		// 处理值为 undefined 或 null 的情况
		if (valueA == null && valueB == null) return 0;
		if (valueA == null) return isAscending ? 1 : -1;
		if (valueB == null) return isAscending ? -1 : 1;

		// 处理字符串和数字的排序
		if (typeof valueA === 'string' && typeof valueB === 'string') {
			return isAscending ? valueA.localeCompare(valueB) : valueB.localeCompare(valueA);
		}
		return isAscending ? valueA - valueB : valueB - valueA;
	});
}
// 测试数据
// const numArray = [3, 1, 2];
// const sortedAsc = sortByKey(numArray, null, true);
// const sortedDesc = sortByKey(numArray, null, false);
// console.log(sortedAsc); // 输出 [1, 2, 3]
// console.log(sortedDesc); // 输出 [3, 2, 1]

/**
 * 对象数组根据多个字段进行升降排序 测试完成
 * @param {Array} arr - 要进行排序的对象数组
 * @param {Array<{ key: string, isAscending: boolean }>} sortConfig - 排序配置数组，每个元素包含用于排序的属性名和是否升序排列
 * @returns {Array} - 排序后的对象数组
 */
function sortByMultipleKeys(arr, sortConfig) {
	// 参数校验
	if (!Array.isArray(arr) || arr.length === 0 || !Array.isArray(sortConfig) || sortConfig.length === 0) {
		return arr;
	}

	return [...arr].sort((a, b) => {
		for (const {
				key,
				isAscending
			}
			of sortConfig) {
			let valueA = a[key];
			let valueB = b[key];

			// 处理值为 undefined 或 null 的情况
			if (valueA == null && valueB == null) continue;
			if (valueA == null) return isAscending ? 1 : -1;
			if (valueB == null) return isAscending ? -1 : 1;

			// 处理字符串和数字的排序
			let comparison;
			if (typeof valueA === 'string' && typeof valueB === 'string') {
				comparison = isAscending ? valueA.localeCompare(valueB) : valueB.localeCompare(valueA);
			} else {
				comparison = isAscending ? valueA - valueB : valueB - valueA;
			}

			if (comparison !== 0) return comparison;
		}
		return 0;
	});
}
// 测试数据
// const data = [
//     { name: 'Alice', age: 20 },
//     { name: 'Bob', age: 25 },
//     { name: 'Alice', age: 22 }
// ];
// // 数组将先按 name 字段升序排序，若 name 相同，则按 age 字段降序排序
// const sortedData = sortByMultipleKeys(data, [
//     { key: 'name', isAscending: true },
//     { key: 'age', isAscending: false }
// ]);
//
// console.log(sortedData);

/**
 * 对象数组根据多个field进行分组，若fields长度为1则单字段分组 测试完成
 * @param {Array<Object>} arr - 要进行分组的对象数组
 * @param {Array<string>} fields - 用于分组的字段名数组
 * @returns {Object} - 分组结果，键为分组依据的值，值为对应的对象数组
 */
export function groupByMultipleFields(arr, fields) {
	// 参数校验
	if (!Array.isArray(arr) || arr.length === 0 || !Array.isArray(fields) || fields.length === 0) {
		return {};
	}

	return arr.reduce((groups, item) => {
		let key;
		if (fields.length === 1) {
			// 单字段分组，直接使用该字段的值
			key = item[fields[0]] || '';
		} else {
			// 多字段分组，拼接多个字段的值
			key = fields.map(field => item[field] || '').join('+');
		}
		if (!groups[key]) {
			groups[key] = [];
		}
		groups[key].push(item);
		return groups;
	}, {});
}
// 测试数据
// const data = [
//     { name: 'Alice', age: 20, city: 'New York' },
//     { name: 'Bob', age: 25, city: 'Los Angeles' },
//     { name: 'Alice', age: 20, city: 'Chicago' }
// ];
// const result = groupByMultipleFields(data, ['name', 'age']);
// console.log(result);

/**
 * 单选框数据不存在回显异常处理方案 测试完成
 * @param valueList 下拉列表数据
 * @param idField 选中id字段名
 * @param nameField 选中name字段名
 * @param selectMap 下拉列表选中单个对象 {selectId: 1, selectName: 'name'}
 * @returns {*}
 */
export function selectSingleValue(valueList, idField, nameField, selectMap) {
	// 增强版参数校验
	if (
		!Array.isArray(valueList) || // 必须为数组
		typeof idField !== 'string' || idField === '' || // 必须为非空字符串
		typeof nameField !== 'string' || nameField === '' ||
		!selectMap || typeof selectMap !== 'object' || Array.isArray(selectMap) // 必须为非空普通对象
	) {
		return valueList || []; // 确保始终返回数组
	}

	// 检查selectId是否在最新列表存在
	const userExists = valueList.some(
		(user) => user[idField] === selectMap[idField]
	);
	// 如果不存在，则创建一个新的数组包含原始数据和新用户数据
	const valueListNew = userExists ?
		valueList // 如果已存在，则直接使用原始数组
		:
		[
			...valueList,
			// 使用 idField, nameField 字段名，创建一个新的用户对象
			{
				[idField]: selectMap[idField],
				[nameField]: selectMap[nameField],
				disabled: true,
			},
		]; // 如果不存在，则添加新用户,disabled: true 为禁用状态
	return valueListNew;
}
// // 测试数据
// const mockValueList = [
//     {id: 1, name: 'Alice'},
//     {id: 2, name: 'Bob'}
// ];
// const idField = 'id';
// const nameField = 'name';
// const validSelectMap = {id: 3, name: 'Charlie'};
// console.log(selectSingleValue(mockValueList, idField, nameField, validSelectMap));
// console.log(selectSingleValue(mockValueList, idField, nameField, null));
// console.log(selectSingleValue(mockValueList, idField, null, validSelectMap));
// console.log(selectSingleValue(mockValueList, null, nameField, validSelectMap));
// console.log(selectSingleValue(null, idField, nameField, validSelectMap));

/**
 * 多选框数据不存在回显异常处理方案 测试完成
 * @param {Array} valueList 下拉列表数据
 * @param {string} idField 选中id字段名
 * @param {string} nameField 选中name字段名
 * @param {Array} selectMapList 下拉列表选中多个对象数组 [{id:1,name:'A'}, {id:2,name:'B'}]
 * @returns {Array}
 */
export function selectMultipleValue(valueList, idField, nameField, selectMapList) {
	// 增强版参数校验
	if (
		!Array.isArray(valueList) || // 必须为数组
		typeof idField !== 'string' || idField === '' || // 必须为非空字符串
		typeof nameField !== 'string' || nameField === '' ||
		!Array.isArray(selectMapList) // 必须为数组
	) {
		return valueList || []; // 确保始终返回数组
	}

	// 过滤掉无效的选中项
	const validSelectedItems = selectMapList.filter(item =>
		item && typeof item === 'object' && !Array.isArray(item)
	);

	// 找出所有不存在的选中项
	const nonExistItems = validSelectedItems.filter(selectedItem =>
		!valueList.some(item => item[idField] === selectedItem[idField])
	);

	// 为不存在的项创建新对象并标记为禁用
	const newItems = nonExistItems.map(item => ({
		[idField]: item[idField],
		[nameField]: item[nameField],
		disabled: true
	}));

	// 合并原始数组和新创建的项
	return [...valueList, ...newItems];
}
// // 测试数据
// // 调用用户复制接口，得到数据列表
// const options = [
//     { id: 1, name: '选项1' },
//     { id: 2, name: '选项2' }
// ];
// // 后端返回的选中项列表，以前返回ids，现在返回对象数组
// const selectedValues = [
//     { id: 1, name: '选项1' },  // 已存在
//     { id: 3, name: '选项3' },  // 不存在
//     { id: 4, name: '选项4' }   // 不存在
// ];
// // 调用函数处理不存在的项,得到最新下拉数据列表
// const result = selectMultipleValue(options, 'id', 'name', selectedValues);
// console.log("Select选择器多选不存在回显异常处理方案-得到最新下拉数据列表:"+JSON.stringify(result));
// // 取出后端返回selectedValues中的id列
// const selectedIds = selectedValues.map(item => item.id);
// console.log("Select选择器多选不存在回显异常处理方案-取出selectedValues中的id列:"+JSON.stringify(selectedIds));
// // 最终手上，有完整的下拉数据列表，和选中项的id列。
